home *** CD-ROM | disk | FTP | other *** search
- // Copyright (C) 1996, 1997 Meta Four Software. All rights reserved.
- //
- // See the comments in "kbound.h" for details on how to use this code.
- //
- //! rev="$Id: kboundw.cpp,v 1.2 1997/05/27 00:06:45 jcw Rel $"
-
- #include "kbound.h"
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // THE LZRW1 ALGORITHM
- // ===================
- // Author : Ross N. Williams.
- // Date : 31-Mar-1991.
- //
- // 1. I typed the following code in from my paper "An Extremely Fast Data
- // Compression Algorithm", Data Compression Conference, Utah, 7-11 April,
- // 1991. The fact that this code works indicates that the code in the
- // paper is OK.
- //
- // 2. This file has been copied into a test harness and works.
- //
- // 3. Some users running old C compilers may wish to insert blanks around
- // the "=" symbols of assignments so as to avoid expressions such as
- // "a=*b;" being interpreted as "a=a*b;"
- //
- // 4. This code is public domain.
- //
- // 5. Warning: This code is non-deterministic insofar as it may yield
- // different compressed representations of the same file on different
- // runs. (However, it will always decompress correctly to the original).
- //
- // 6. If you use this code in anger (e.g. in a product) drop me a note at
- // ross@spam.ua.oz.au and I will put you on a mailing list which will be
- // invoked if anyone finds a bug in this code.
- //
- // 7. The internet newsgroup comp.compression might also carry
- // information on this algorithm from time to time.
- //
- /////////////////////////////////////////////////////////////////////////////
-
- #define FLAG_BYTES 2 /* Number of bytes used by copy flag. */
- #define FLAG_COMPRESS 0 /* Signals that compression occurred. */
- #define FLAG_COPY 1 /* Signals that a copyover occurred. */
- static void fast_copy(BYTE *p_src,BYTE *p_dst,int len) /* Fast copy routine. */
- {while (len--) *p_dst++=*p_src++;}
-
- void lzrw1_compress(BYTE *p_src_first,DWORD src_len,
- BYTE *p_dst_first,DWORD *p_dst_len)
- /* Input : Specify input block using p_src_first and src_len. */
- /* Input : Point p_dst_first to the start of the output zone (OZ). */
- /* Input : Point p_dst_len to a DWORD to receive the output length. */
- /* Input : Input block and output zone must not overlap. */
- /* Output : Length of output block written to *p_dst_len. */
- /* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
- /* Output : May write in OZ=Mem[p_dst_first..p_dst_first+src_len+256-1].*/
- /* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */
- #define PS *p++!=*s++ /* Body of inner unrolled matching loop. */
- #define ITEMMAX 16 /* Maximum number of bytes in an expanded item. */
- {BYTE *p_src=p_src_first,*p_dst=p_dst_first;
- BYTE *p_src_post=p_src_first+src_len,*p_dst_post=p_dst_first+src_len;
- BYTE *p_src_max1=p_src_post-ITEMMAX,*p_src_max16=p_src_post-16*ITEMMAX;
- BYTE *hash[4096],*p_control; WORD control=0,control_bits=0;
- *p_dst=FLAG_COMPRESS; p_dst+=FLAG_BYTES; p_control=p_dst; p_dst+=2;
- while (1)
- {BYTE *p,*s; WORD unroll=16,len,index; DWORD offset;
- if (p_dst>p_dst_post) goto overrun;
- if (p_src>p_src_max16)
- {unroll=1;
- if (p_src>p_src_max1)
- {if (p_src==p_src_post) break; goto literal;}}
- begin_unrolled_loop:
- index=((40543*((((p_src[0]<<4)^p_src[1])<<4)^p_src[2]))>>4) & 0xFFF;
- p=hash[index]; hash[index]=s=p_src; offset=s-p;
- if (offset>4095 || p<p_src_first || offset==0 || PS || PS || PS)
- {literal: *p_dst++=*p_src++; control>>=1; control_bits++;}
- else
- {PS || PS || PS || PS || PS || PS || PS ||
- PS || PS || PS || PS || PS || PS || s++; len=s-p_src-1;
- *p_dst++=(BYTE) (((offset&0xF00)>>4)+(len-1));
- *p_dst++=(BYTE) (offset&0xFF);
- p_src+=len; control=(control>>1)|0x8000; control_bits++;}
- /* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop;
- if (control_bits==16)
- {*p_control=control&0xFF; *(p_control+1)=control>>8;
- p_control=p_dst; p_dst+=2; control=control_bits=0;}
- }
- control>>=16-control_bits;
- *p_control++=control&0xFF; *p_control++=control>>8;
- if (p_control==p_dst) p_dst-=2;
- *p_dst_len=p_dst-p_dst_first;
- return;
- overrun: fast_copy(p_src_first,p_dst_first+FLAG_BYTES,(int)src_len);
- *p_dst_first=FLAG_COPY; *p_dst_len=src_len+FLAG_BYTES;
- }
-
- /////////////////////////////////////////////////////////////////////////////
-
- class c4_BoundWriter : public CFile
- {
- BYTE *_begin, *_curr, *_end;
- int _base;
- CString _prefix;
- CString _resIncText;
- bool _asText;
-
- public:
- c4_BoundWriter (const char* prefix_, bool asText_, int base_)
- : _prefix (prefix_), _asText (asText_), _base (base_)
- {
- _begin = _curr = new BYTE [c4_BoundStorage::kBlockSize];
- _end = _begin + c4_BoundStorage::kBlockSize;
- }
-
- virtual ~c4_BoundWriter ()
- {
- FlushNextBlock();
-
- delete [] _begin;
-
- CFile out (_prefix + ".rc", CFile::modeWrite | CFile::modeCreate);
- out.Write((const char*) _resIncText, _resIncText.GetLength());
- }
-
- virtual UINT Read(void* lpBuf, UINT nCount)
- {
- ASSERT(0);
- return 0;
- }
-
- virtual void Write(const void* lpBuf, UINT nCount)
- {
- UINT n = nCount;
-
- while (n > 0)
- {
- if (_curr >= _end)
- FlushNextBlock();
-
- int k = n;
- if (k > _end - _curr)
- k = _end - _curr;
-
- memcpy(_curr, lpBuf, k);
-
- _curr += k;
- lpBuf = (const char*) lpBuf + k;
- n -= k;
- }
- }
-
- void FlushNextBlock()
- {
- if (_curr > _begin)
- {
- DWORD k = _curr - _begin;
- ASSERT(k <= c4_BoundStorage::kBlockSize);
-
- _curr = _begin;
-
- c4_Bytes temp;
- BYTE* tempBuf = temp.SetBuffer((int) k + 256 + FLAG_BYTES);
-
- lzrw1_compress(_begin, k, tempBuf, &k);
- ASSERT((int) k <= temp.Size() - 4);
-
- ASSERT((int) k <= c4_BoundStorage::kBlockSize + FLAG_BYTES);
- ASSERT(*tempBuf <= 1);
-
- // save the exact stored length and the copy bit
- *(WORD*) tempBuf = ((WORD) k << 1) + *tempBuf;
-
- ASSERT(c4_BoundStorage::_Encoder);
- c4_BoundStorage::_Encoder(true, _base - 1,
- (char*) tempBuf + 2, k - 2);
-
- char num [20];
- wsprintf(num, "%03d", _base);
- CString s = num;
-
- if (_asText)
- {
- CFile out (_prefix + s + ".rc",
- CFile::modeWrite | CFile::modeCreate);
-
- CString line = s + " RCDATA\r\nBEGIN";
-
- memset(tempBuf + k, 0, 4); // make sure trailing bytes are zero
-
- for (WORD i = 0; i < k; i += sizeof (DWORD))
- {
- if (i % 32 == 0)
- {
- out.Write(line, line.GetLength());
- line = "\r\n ";
- }
-
- wsprintf(num, "0x%08lxL,", *(const DWORD*) (tempBuf + i));
-
- line += num;
- }
-
- line += "\r\nEND\r\n";
- out.Write(line, line.GetLength());
-
- _resIncText += "#include \"" + _prefix + s + ".rc\"\r\n";
- }
- else
- {
- CFile out (_prefix + s + ".res",
- CFile::modeWrite | CFile::modeCreate);
-
- out.Write(tempBuf, k);
-
- _resIncText += s + " RCDATA \"" + _prefix + s + ".res\"\r\n";
- }
- }
-
- ++_base;
- }
- };
-
- /////////////////////////////////////////////////////////////////////////////
-
- int c4_BoundStorage::DumpAsRes(c4_Storage& orig_, const char* prefix_,
- bool asText_, int base_)
- {
- c4_BoundWriter writer (prefix_, asText_, base_);
- orig_.SaveToStream(&writer);
- return 0;
- }
-
- /////////////////////////////////////////////////////////////////////////////
-